
#include "Grid.h"


#ifdef _DEBUG
   #define new MYDEBUG_NEW
#endif

namespace GridSolver
{

int StateIndex::dimension; 
int State::actionsNumber; 
long State::totalNumberOfStates ; 
StateIndex State::fictituousState; 
StateIndex State::sinkState; 
FILE* StateAction::logFile; 

StateIndex::StateIndex()
{
		for(int i=0; i< MAX_DIMENSION; i++)
			index[i] = -1;
}

StateAction::StateAction()
{
	qvalue = 0; 
	isKnown = false; 
	totalVisits = 0; 

	//optimistic initialization 
	reward = 0;	

	transProbs[State::fictituousState] = pair<double,double>(1,0); 
}

//tvisit is the total number of visits in the l 
void StateAction::buildTransitionProbs(countMap& l, int tvisits, double knownness)
{
	transProbs.clear();

	//add the fictituous transition
	if (l.empty())
	{
		transProbs[State::fictituousState] = pair<double,double>(1,0); 
		return; 
	}


	for(countMap::iterator it = l.begin(); it != l.end(); it++)
	{
		double prob = (*it).second.first/ (double) tvisits * knownness; 
		transProbs.insert(doublePair((*it).first, pair<double,double>(prob,(*it).second.second) )); 
//		(*pit).second.first /= (double) totalVisits; 
	}//for

	if (knownness < 1)
	{
		transProbs[State::fictituousState] = pair<double,double>(1- knownness,0); 
	}

}


void StateAction::makeKnown()
{
	isKnown = true ; 

	//log some information
/*	if (!flag)
	{
		fprintf(logFile,"estimate says: reward: %lf \n", reward); 
		for(probMap::iterator it = transProbs.begin(); it != transProbs.end(); it++)
		{
			fprintf(logFile,"["); 
			for(int i=0; i< StateIndex::dimension; i++)
				fprintf(logFile,"%d,",(*it).first.index[i]); 

			fprintf(logFile,"]  p: %lf r: %lf\n", (*it).second.first, (*it).second.second); 
	//		fprintf(logFile, "%s p: %lf r: %lf\n", (*it).first.toString(), (*it).second.first, (*it).second.second); 
		}

	}
*/

	buildTransitionProbs(transCounts, totalVisits, 1); 
	reward = computeReward(); 

/*	if (!flag)
	{
		fprintf(logFile,"experience says: \n"); 
		for(probMap::iterator it = transProbs.begin(); it != transProbs.end(); it++)
		{
			fprintf(logFile,"["); 
			for(int i=0; i< StateIndex::dimension; i++)
				fprintf(logFile,"%d,",(*it).first.index[i]); 

			fprintf(logFile,"]  p: %lf r: %lf\n", (*it).second.first, (*it).second.second); 
	//		fprintf(logFile, "%s p: %lf r: %lf\n", (*it).first.toString(), (*it).second.first, (*it).second.second); 
		}
	}
*/
}//


void StateAction::addToCountList(countMap& l, const StateIndex& st, double rw)
{
	countMap::iterator it = l.find(st);
	if (it != l.end())	//already there
	{
//		printf("i've seen it before...\n"); 
		//update the counter
		int times = (*it).second.first;
		(*it).second.first++;
		//update the average reward
		(*it).second.second = ((*it).second.second * times  + rw) / (times+1); 
	}
	else
	{
		l.insert(intPair(st,pair<int,double>(1,rw)));
	}
}

//returns true if this update causes this state to become known, false otherwise
bool StateAction::updateTransCounts(const StateIndex& st, double rw)
{


	addToCountList(transCounts, st, rw); 

	totalVisits++; 

	if (totalVisits >= ParamReader::RMAX_KNOWN_THRESHOLD)
	{
		bool t = ! isKnown;
		return t; 
	}
	
	return false; 

}//

bool StateIndex::operator <(const StateIndex& rhs) const
{
	for(int i=0; i< dimension ; i++)
		if(index[i] < rhs.index[i])
			return true; 
		else if (index[i] > rhs.index[i]) 
			return false; 

	return false; 	
}

bool StateIndex::operator ==(const StateIndex& rhs) const
{
	for(int i=0; i< dimension ; i++)
		if(index[i] != rhs.index[i])
			return false; 
	return true; 	
}


bool StateIndex::operator !=(const StateIndex& rhs) const
{
	return ! operator == (rhs); 

}

double StateAction::computeReward()
{
	double result = 0; 
	for(probMap::iterator it = transProbs.begin(); it != transProbs.end(); it++)
	{
		result += (*it).second.first * (*it).second.second; 

	}
	return result; 
}

//returns the inner distance between all of it's targets
double StateAction::innerDistance()
{
	double result = 0; 
	
	if (totalVisits ==0)
		return 0; 

	for(countMap::iterator it = transCounts.begin(); it!= transCounts.end(); it++)
		for(countMap::iterator tit = it; tit != transCounts.end(); tit++)
		{
			int count = (*it).second.first + (*tit).second.first; 
			if (count > 0)
				result += StateIndex::l1distance((*it).first, (*tit).first) / (double) count;
		}

	return result; 
}

void StateAction::print()
{
	printf("\tqval: %lf visits: %d\n", qvalue, totalVisits); 
	for(probMap::iterator it = transProbs.begin(); it != transProbs.end(); it++)
	{
		printf("\t\t["); 
		for(int i=0; i< StateIndex::dimension; i++)
			printf("%d,",(*it).first.index[i]); 

		printf("]  p: %lf r: %lf\n", (*it).second.first, (*it).second.second); 
//		fprintf(logFile, "%s p: %lf r: %lf\n", (*it).first.toString(), (*it).second.first, (*it).second.second); 
	}
}


double StateIndex::l1distance(const StateIndex& lhs, const StateIndex& rhs)
{
	double result = 0; 
	for(int i=0; i< dimension; i++)
		result += abs(lhs.index[i] -rhs.index[i]); 

	return result; 
}


void State::print()
{
	printf("value: %lf policy %d\n", value, policy); 
	for(int i=0; i< actionsNumber; i++)
		actions[i].print(); 

}


}
